package com.ruoyi.common.core.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.service.IBaseService;
import org.apache.commons.collections4.CollectionUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;

/**
 * TODO 自定义
 *
 * @param <T>
 * @author zhengyz
 */
public class IBaseServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements IBaseService<T> {

    @Override
    public T getById(Serializable id) {
        return super.getById(Assert.notNull(id, Constants.NO_DATA_DESC));
    }

    @Override
    public T getByIdOrThrow(Serializable id) {
        return Assert.notNull(getById(id), Constants.NO_DATA_DESC);
    }

    @Override
    public T getByIdOrThrow(Serializable id, String errorMsgTemplate, Object... params) {
        return Assert.notNull(getById(id), errorMsgTemplate, params);
    }

    @Override
    public T getByIdOrThrow(Serializable id, Class<T> clazz, String... ignoreProperties) {
        return BeanUtil.copyProperties(getByIdOrThrow(id), clazz, ignoreProperties);
    }

    @Override
    public T getByIdOrNewInstance(Serializable id, Class<T> clazz) {
        T entity = getById(id);
        return entity != null ? entity : ReflectUtil.newInstanceIfPossible(clazz);
    }

    @Override
    public List<T> listByIdsOrThrow(Collection<? extends Serializable> ids) {
        return Assert.notEmpty(listByIds(Assert.notEmpty(ids)), Constants.NO_DATA_DESC);
    }

    @Override
    public boolean saveBatch(Collection<T> entityList) {
        return !CollectionUtils.isEmpty(entityList) && super.saveBatch(entityList);
    }

    @Override
    public boolean saveOrUpdateBatch(Collection<T> entityList) {
        return !CollectionUtils.isEmpty(entityList) && super.saveOrUpdateBatch(entityList);
    }

    @Override
    public boolean updateBatchById(Collection<T> entityList) {
        return !CollectionUtils.isEmpty(entityList) && super.updateBatchById(entityList);
    }

    @Override
    public boolean saveOrUpdate(T entity) {
        BeanUtil.trimStrFields(entity);
        return super.saveOrUpdate(entity);
    }

    @Override
    public boolean removeById(Serializable id) {
        return super.removeById(Assert.notNull(id, Constants.NO_DATA_DESC));
    }

    @Override
    public boolean removeByIds(Collection<?> list) {
        return super.removeByIds(Assert.notEmpty(list, Constants.NO_DATA_DESC));
    }

    public <T> QueryWrapper<T> listQueryWrapper(T t) {
        QueryWrapper<T> dataWrapper = new QueryWrapper<>();
        Class<?> clazz = t.getClass();
        // 获取所有字段，包括私有字段
        Field[] fields = clazz.getDeclaredFields();
        Class<?> parentClass = clazz.getSuperclass();
        Field[] parentFields = parentClass.getDeclaredFields();
        for (Field field : fields) {
            setQueryWrapper(dataWrapper, field, t);
        }
        for (Field field : parentFields) {
            setQueryWrapper(dataWrapper, field, t);
        }
        return dataWrapper;
    }

    <T> void setQueryWrapper(QueryWrapper<T> dataWrapper, Field field, T t) {
        if ("serialVersionUID".equals(field.getName())) {
            return;
        }
        field.setAccessible(true); // 设置私有字段可访问
        Object value = null; // 获取字段值
        try {
            value = field.get(t);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        if (ObjectUtil.isNotEmpty(value)) { // 检查值是否不为null
            if ("searchValue".equals(field.getName())) {
                dataWrapper.select(value.toString());
            } else if (field.getName().contains("Name") || field.getName().contains("name")) {
                dataWrapper.likeRight(StrUtil.toUnderlineCase(field.getName()), value);
            } else {
                dataWrapper.eq(StrUtil.toUnderlineCase(field.getName()), value);
            }
        }
    }
}
